home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-ALPH.{_4 / PGTABLE.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  20KB  |  657 lines

  1. #ifndef _ALPHA_PGTABLE_H
  2. #define _ALPHA_PGTABLE_H
  3.  
  4. /*
  5.  * This file contains the functions and defines necessary to modify and use
  6.  * the Alpha page table tree.
  7.  *
  8.  * This hopefully works with any standard Alpha page-size, as defined
  9.  * in <asm/page.h> (currently 8192).
  10.  */
  11. #include <linux/config.h>
  12.  
  13. #include <asm/system.h>
  14. #include <asm/processor.h>    /* For TASK_SIZE */
  15. #include <asm/mmu_context.h>
  16. #include <asm/machvec.h>
  17. #include <asm/spinlock.h>    /* For the task lock */
  18.  
  19.  
  20. /* Caches aren't brain-dead on the Alpha. */
  21. #define flush_cache_all()            do { } while (0)
  22. #define flush_cache_mm(mm)            do { } while (0)
  23. #define flush_cache_range(mm, start, end)    do { } while (0)
  24. #define flush_cache_page(vma, vmaddr)        do { } while (0)
  25. #define flush_page_to_ram(page)            do { } while (0)
  26. #define flush_icache_range(start, end)        do { } while (0)
  27.  
  28. /*
  29.  * Use a few helper functions to hide the ugly broken ASN
  30.  * numbers on early Alphas (ev4 and ev45)
  31.  */
  32.  
  33. #ifndef __EXTERN_INLINE
  34. #define __EXTERN_INLINE extern inline
  35. #define __MMU_EXTERN_INLINE
  36. #endif
  37.  
  38. __EXTERN_INLINE void
  39. ev4_flush_tlb_current(struct mm_struct *mm)
  40. {
  41.     tbiap();
  42. }
  43.  
  44. __EXTERN_INLINE void
  45. ev4_flush_tlb_other(struct mm_struct *mm)
  46. {
  47. }
  48.  
  49. __EXTERN_INLINE void
  50. ev5_flush_tlb_current(struct mm_struct *mm)
  51. {
  52.     mm->context = 0;
  53.     get_new_mmu_context(current, mm);
  54.     reload_context(current);
  55. }
  56.  
  57. __EXTERN_INLINE void
  58. ev5_flush_tlb_other(struct mm_struct *mm)
  59. {
  60.     mm->context = 0;
  61. }
  62.  
  63. /*
  64.  * Flush just one page in the current TLB set.
  65.  * We need to be very careful about the icache here, there
  66.  * is no way to invalidate a specific icache page..
  67.  */
  68.  
  69. __EXTERN_INLINE void
  70. ev4_flush_tlb_current_page(struct mm_struct * mm,
  71.                struct vm_area_struct *vma,
  72.                unsigned long addr)
  73. {
  74.     tbi(2 + ((vma->vm_flags & VM_EXEC) != 0), addr);
  75. }
  76.  
  77. __EXTERN_INLINE void
  78. ev5_flush_tlb_current_page(struct mm_struct * mm,
  79.                struct vm_area_struct *vma,
  80.                unsigned long addr)
  81. {
  82.     if (vma->vm_flags & VM_EXEC)
  83.         ev5_flush_tlb_current(mm);
  84.     else
  85.         tbi(2, addr);
  86. }
  87.  
  88.  
  89. #ifdef CONFIG_ALPHA_GENERIC
  90. # define flush_tlb_current        alpha_mv.mv_flush_tlb_current
  91. # define flush_tlb_other        alpha_mv.mv_flush_tlb_other
  92. # define flush_tlb_current_page        alpha_mv.mv_flush_tlb_current_page
  93. #else
  94. # ifdef CONFIG_ALPHA_EV4
  95. #  define flush_tlb_current        ev4_flush_tlb_current
  96. #  define flush_tlb_other        ev4_flush_tlb_other
  97. #  define flush_tlb_current_page    ev4_flush_tlb_current_page
  98. # else
  99. #  define flush_tlb_current        ev5_flush_tlb_current
  100. #  define flush_tlb_other        ev5_flush_tlb_other
  101. #  define flush_tlb_current_page    ev5_flush_tlb_current_page
  102. # endif
  103. #endif
  104.  
  105. #ifdef __MMU_EXTERN_INLINE
  106. #undef __EXTERN_INLINE
  107. #undef __MMU_EXTERN_INLINE
  108. #endif
  109.  
  110. /*
  111.  * Flush current user mapping.
  112.  */
  113. static inline void flush_tlb(void)
  114. {
  115.     flush_tlb_current(current->mm);
  116. }
  117.  
  118. #ifndef __SMP__
  119. /*
  120.  * Flush everything (kernel mapping may also have
  121.  * changed due to vmalloc/vfree)
  122.  */
  123. static inline void flush_tlb_all(void)
  124. {
  125.     tbia();
  126. }
  127.  
  128. /*
  129.  * Flush a specified user mapping
  130.  */
  131. static inline void flush_tlb_mm(struct mm_struct *mm)
  132. {
  133.     if (mm != current->mm)
  134.         flush_tlb_other(mm);
  135.     else
  136.         flush_tlb_current(mm);
  137. }
  138.  
  139. /*
  140.  * Page-granular tlb flush.
  141.  *
  142.  * do a tbisd (type = 2) normally, and a tbis (type = 3)
  143.  * if it is an executable mapping.  We want to avoid the
  144.  * itlb flush, because that potentially also does a
  145.  * icache flush.
  146.  */
  147. static inline void flush_tlb_page(struct vm_area_struct *vma,
  148.     unsigned long addr)
  149. {
  150.     struct mm_struct * mm = vma->vm_mm;
  151.  
  152.     if (mm != current->mm)
  153.         flush_tlb_other(mm);
  154.     else
  155.         flush_tlb_current_page(mm, vma, addr);
  156. }
  157.  
  158. /*
  159.  * Flush a specified range of user mapping:  on the
  160.  * Alpha we flush the whole user tlb.
  161.  */
  162. static inline void flush_tlb_range(struct mm_struct *mm,
  163.     unsigned long start, unsigned long end)
  164. {
  165.     flush_tlb_mm(mm);
  166. }
  167.  
  168. #else /* __SMP__ */
  169.  
  170. /* ipi_msg_flush_tb is owned by the holder of the global kernel lock. */
  171. struct ipi_msg_flush_tb_struct {
  172.     volatile unsigned int flush_tb_mask;
  173.     union {
  174.         struct mm_struct *    flush_mm;
  175.         struct vm_area_struct *    flush_vma;
  176.     } p;
  177.     unsigned long flush_addr;
  178.     unsigned long flush_end;
  179. };
  180.  
  181. extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
  182.  
  183. extern void flush_tlb_all(void);
  184. extern void flush_tlb_mm(struct mm_struct *);
  185. extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
  186. extern void flush_tlb_range(struct mm_struct *, unsigned long, unsigned long);
  187.  
  188. #endif /* __SMP__ */
  189.  
  190. /* Certain architectures need to do special things when PTEs
  191.  * within a page table are directly modified.  Thus, the following
  192.  * hook is made available.
  193.  */
  194. #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
  195.  
  196. /* PMD_SHIFT determines the size of the area a second-level page table can map */
  197. #define PMD_SHIFT    (PAGE_SHIFT + (PAGE_SHIFT-3))
  198. #define PMD_SIZE    (1UL << PMD_SHIFT)
  199. #define PMD_MASK    (~(PMD_SIZE-1))
  200.  
  201. /* PGDIR_SHIFT determines what a third-level page table entry can map */
  202. #define PGDIR_SHIFT    (PAGE_SHIFT + 2*(PAGE_SHIFT-3))
  203. #define PGDIR_SIZE    (1UL << PGDIR_SHIFT)
  204. #define PGDIR_MASK    (~(PGDIR_SIZE-1))
  205.  
  206. /*
  207.  * Entries per page directory level:  the Alpha is three-level, with
  208.  * all levels having a one-page page table.
  209.  *
  210.  * The PGD is special:  the last entry is reserved for self-mapping.
  211.  */
  212. #define PTRS_PER_PTE    (1UL << (PAGE_SHIFT-3))
  213. #define PTRS_PER_PMD    (1UL << (PAGE_SHIFT-3))
  214. #define PTRS_PER_PGD    ((1UL << (PAGE_SHIFT-3))-1)
  215. #define USER_PTRS_PER_PGD    (TASK_SIZE / PGDIR_SIZE)
  216.  
  217. /* Number of pointers that fit on a page:  this will go away. */
  218. #define PTRS_PER_PAGE    (1UL << (PAGE_SHIFT-3))
  219.  
  220. #define VMALLOC_START        0xFFFFFE0000000000
  221. #define VMALLOC_VMADDR(x)    ((unsigned long)(x))
  222. #define VMALLOC_END        (~0UL)
  223.  
  224. /*
  225.  * OSF/1 PAL-code-imposed page table bits
  226.  */
  227. #define _PAGE_VALID    0x0001
  228. #define _PAGE_FOR    0x0002    /* used for page protection (fault on read) */
  229. #define _PAGE_FOW    0x0004    /* used for page protection (fault on write) */
  230. #define _PAGE_FOE    0x0008    /* used for page protection (fault on exec) */
  231. #define _PAGE_ASM    0x0010
  232. #define _PAGE_KRE    0x0100    /* xxx - see below on the "accessed" bit */
  233. #define _PAGE_URE    0x0200    /* xxx */
  234. #define _PAGE_KWE    0x1000    /* used to do the dirty bit in software */
  235. #define _PAGE_UWE    0x2000    /* used to do the dirty bit in software */
  236.  
  237. /* .. and these are ours ... */
  238. #define _PAGE_DIRTY    0x20000
  239. #define _PAGE_ACCESSED    0x40000
  240.  
  241. /*
  242.  * NOTE! The "accessed" bit isn't necessarily exact:  it can be kept exactly
  243.  * by software (use the KRE/URE/KWE/UWE bits appropriately), but I'll fake it.
  244.  * Under Linux/AXP, the "accessed" bit just means "read", and I'll just use
  245.  * the KRE/URE bits to watch for it. That way we don't need to overload the
  246.  * KWE/UWE bits with both handling dirty and accessed.
  247.  *
  248.  * Note that the kernel uses the accessed bit just to check whether to page
  249.  * out a page or not, so it doesn't have to be exact anyway.
  250.  */
  251.  
  252. #define __DIRTY_BITS    (_PAGE_DIRTY | _PAGE_KWE | _PAGE_UWE)
  253. #define __ACCESS_BITS    (_PAGE_ACCESSED | _PAGE_KRE | _PAGE_URE)
  254.  
  255. #define _PFN_MASK    0xFFFFFFFF00000000
  256.  
  257. #define _PAGE_TABLE    (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
  258. #define _PAGE_CHG_MASK    (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
  259.  
  260. /*
  261.  * All the normal masks have the "page accessed" bits on, as any time they are used,
  262.  * the page is accessed. They are cleared only by the page-out routines
  263.  */
  264. #define PAGE_NONE    __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
  265. #define PAGE_SHARED    __pgprot(_PAGE_VALID | __ACCESS_BITS)
  266. #define PAGE_COPY    __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
  267. #define PAGE_READONLY    __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
  268. #define PAGE_KERNEL    __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE)
  269.  
  270. #define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
  271.  
  272. #define _PAGE_P(x) _PAGE_NORMAL((x) | (((x) & _PAGE_FOW)?0:_PAGE_FOW))
  273. #define _PAGE_S(x) _PAGE_NORMAL(x)
  274.  
  275. /*
  276.  * The hardware can handle write-only mappings, but as the Alpha
  277.  * architecture does byte-wide writes with a read-modify-write
  278.  * sequence, it's not practical to have write-without-read privs.
  279.  * Thus the "-w- -> rw-" and "-wx -> rwx" mapping here (and in
  280.  * arch/alpha/mm/fault.c)
  281.  */
  282.     /* xwr */
  283. #define __P000    _PAGE_P(_PAGE_FOE | _PAGE_FOW | _PAGE_FOR)
  284. #define __P001    _PAGE_P(_PAGE_FOE | _PAGE_FOW)
  285. #define __P010    _PAGE_P(_PAGE_FOE)
  286. #define __P011    _PAGE_P(_PAGE_FOE)
  287. #define __P100    _PAGE_P(_PAGE_FOW | _PAGE_FOR)
  288. #define __P101    _PAGE_P(_PAGE_FOW)
  289. #define __P110    _PAGE_P(0)
  290. #define __P111    _PAGE_P(0)
  291.  
  292. #define __S000    _PAGE_S(_PAGE_FOE | _PAGE_FOW | _PAGE_FOR)
  293. #define __S001    _PAGE_S(_PAGE_FOE | _PAGE_FOW)
  294. #define __S010    _PAGE_S(_PAGE_FOE)
  295. #define __S011    _PAGE_S(_PAGE_FOE)
  296. #define __S100    _PAGE_S(_PAGE_FOW | _PAGE_FOR)
  297. #define __S101    _PAGE_S(_PAGE_FOW)
  298. #define __S110    _PAGE_S(0)
  299. #define __S111    _PAGE_S(0)
  300.  
  301. /*
  302.  * BAD_PAGETABLE is used when we need a bogus page-table, while
  303.  * BAD_PAGE is used for a bogus page.
  304.  *
  305.  * ZERO_PAGE is a global shared page that is always zero:  used
  306.  * for zero-mapped memory areas etc..
  307.  */
  308. extern pte_t __bad_page(void);
  309. extern pmd_t * __bad_pagetable(void);
  310.  
  311. extern unsigned long __zero_page(void);
  312.  
  313. #define BAD_PAGETABLE    __bad_pagetable()
  314. #define BAD_PAGE    __bad_page()
  315. #define ZERO_PAGE    (PAGE_OFFSET+0x30A000)
  316.  
  317. /* number of bits that fit into a memory pointer */
  318. #define BITS_PER_PTR            (8*sizeof(unsigned long))
  319.  
  320. /* to align the pointer to a pointer address */
  321. #define PTR_MASK            (~(sizeof(void*)-1))
  322.  
  323. /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
  324. #define SIZEOF_PTR_LOG2            3
  325.  
  326. /* to find an entry in a page-table */
  327. #define PAGE_PTR(address)        \
  328.   ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
  329.  
  330. /*
  331.  * On certain platforms whose physical address space can overlap KSEG,
  332.  * namely EV6 and above, we must re-twiddle the physaddr to restore the
  333.  * correct high-order bits.
  334.  */
  335.  
  336. #if defined(CONFIG_ALPHA_GENERIC) && defined(USE_48_BIT_KSEG)
  337. #error "EV6-only feature in a generic kernel"
  338. #endif
  339. #if defined(CONFIG_ALPHA_GENERIC) || \
  340.     (defined(CONFIG_ALPHA_EV6) && !defined(USE_48_BIT_KSEG))
  341. #define PHYS_TWIDDLE(phys) \
  342.   ((((phys) & 0xc0000000000UL) == 0x40000000000UL) \
  343.   ? ((phys) ^= 0xc0000000000UL) : (phys))
  344. #else
  345. #define PHYS_TWIDDLE(phys) (phys)
  346. #endif
  347.  
  348. /*
  349.  * Conversion functions:  convert a page and protection to a page entry,
  350.  * and a page entry and page directory to the page they refer to.
  351.  */
  352. extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
  353. { pte_t pte; pte_val(pte) = ((page-PAGE_OFFSET) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
  354.  
  355. extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
  356. { pte_t pte; pte_val(pte) = (PHYS_TWIDDLE(physpage) << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
  357.  
  358. extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  359. { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
  360.  
  361. extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
  362. { pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
  363.  
  364. extern inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp)
  365. { pgd_val(*pgdp) = _PAGE_TABLE | ((((unsigned long) pmdp) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
  366.  
  367. extern inline unsigned long pte_page(pte_t pte)
  368. { return PAGE_OFFSET + ((pte_val(pte) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
  369.  
  370. extern inline unsigned long pmd_page(pmd_t pmd)
  371. { return PAGE_OFFSET + ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
  372.  
  373. extern inline unsigned long pgd_page(pgd_t pgd)
  374. { return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
  375.  
  376. extern inline int pte_none(pte_t pte)        { return !pte_val(pte); }
  377. extern inline int pte_present(pte_t pte)    { return pte_val(pte) & _PAGE_VALID; }
  378. extern inline void pte_clear(pte_t *ptep)    { pte_val(*ptep) = 0; }
  379.  
  380. extern inline int pmd_none(pmd_t pmd)        { return !pmd_val(pmd); }
  381. extern inline int pmd_bad(pmd_t pmd)        { return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE; }
  382. extern inline int pmd_present(pmd_t pmd)    { return pmd_val(pmd) & _PAGE_VALID; }
  383. extern inline void pmd_clear(pmd_t * pmdp)    { pmd_val(*pmdp) = 0; }
  384.  
  385. extern inline int pgd_none(pgd_t pgd)        { return !pgd_val(pgd); }
  386. extern inline int pgd_bad(pgd_t pgd)        { return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE; }
  387. extern inline int pgd_present(pgd_t pgd)    { return pgd_val(pgd) & _PAGE_VALID; }
  388. extern inline void pgd_clear(pgd_t * pgdp)    { pgd_val(*pgdp) = 0; }
  389.  
  390. /*
  391.  * The following only work if pte_present() is true.
  392.  * Undefined behaviour if not..
  393.  */
  394. extern inline int pte_read(pte_t pte)        { return !(pte_val(pte) & _PAGE_FOR); }
  395. extern inline int pte_write(pte_t pte)        { return !(pte_val(pte) & _PAGE_FOW); }
  396. extern inline int pte_exec(pte_t pte)        { return !(pte_val(pte) & _PAGE_FOE); }
  397. extern inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
  398. extern inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
  399.  
  400. extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_FOW; return pte; }
  401. extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) |= _PAGE_FOR; return pte; }
  402. extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) |= _PAGE_FOE; return pte; }
  403. extern inline pte_t pte_mkclean(pte_t pte)    { pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
  404. extern inline pte_t pte_mkold(pte_t pte)    { pte_val(pte) &= ~(__ACCESS_BITS); return pte; }
  405. extern inline pte_t pte_mkwrite(pte_t pte)    { pte_val(pte) &= ~_PAGE_FOW; return pte; }
  406. extern inline pte_t pte_mkread(pte_t pte)    { pte_val(pte) &= ~_PAGE_FOR; return pte; }
  407. extern inline pte_t pte_mkexec(pte_t pte)    { pte_val(pte) &= ~_PAGE_FOE; return pte; }
  408. extern inline pte_t pte_mkdirty(pte_t pte)    { pte_val(pte) |= __DIRTY_BITS; return pte; }
  409. extern inline pte_t pte_mkyoung(pte_t pte)    { pte_val(pte) |= __ACCESS_BITS; return pte; }
  410.  
  411. /* 
  412.  * To set the page-dir. Note the self-mapping in the last entry
  413.  *
  414.  * Also note that if we update the current process ptbr, we need to
  415.  * update the PAL-cached ptbr value as well.. There doesn't seem to
  416.  * be any "wrptbr" PAL-insn, but we can do a dummy swpctx to ourself
  417.  * instead.
  418.  */
  419. extern inline void SET_PAGE_DIR(struct task_struct * tsk, pgd_t * pgdir)
  420. {
  421.     pgd_val(pgdir[PTRS_PER_PGD]) = pte_val(mk_pte((unsigned long) pgdir, PAGE_KERNEL));
  422.     tsk->tss.ptbr = ((unsigned long) pgdir - PAGE_OFFSET) >> PAGE_SHIFT;
  423.     if (tsk == current)
  424.         reload_context(tsk);
  425. }
  426.  
  427. #define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
  428.  
  429. /* to find an entry in a kernel page-table-directory */
  430. #define pgd_offset_k(address) pgd_offset(&init_mm, address)
  431.  
  432. /* to find an entry in a page-table-directory. */
  433. extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
  434. {
  435.     return mm->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1));
  436. }
  437.  
  438. /* Find an entry in the second-level page table.. */
  439. extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
  440. {
  441.     return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
  442. }
  443.  
  444. /* Find an entry in the third-level page table.. */
  445. extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
  446. {
  447.     return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1));
  448. }
  449.  
  450. /*      
  451.  * Allocate and free page tables. The xxx_kernel() versions are
  452.  * used to allocate a kernel page table - this turns on ASN bits
  453.  * if any.
  454.  */
  455. #ifndef __SMP__
  456. extern struct pgtable_cache_struct {
  457.     unsigned long *pgd_cache;
  458.     unsigned long *pte_cache;
  459.     unsigned long pgtable_cache_sz;
  460. } quicklists;
  461. #else
  462. #include <asm/smp.h>
  463. #define quicklists cpu_data[smp_processor_id()]
  464. #endif
  465. #define pgd_quicklist (quicklists.pgd_cache)
  466. #define pmd_quicklist ((unsigned long *)0)
  467. #define pte_quicklist (quicklists.pte_cache)
  468. #define pgtable_cache_size (quicklists.pgtable_cache_sz)
  469.  
  470. extern __inline__ pgd_t *get_pgd_slow(void)
  471. {
  472.     pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL), *init;
  473.     
  474.     if (ret) {
  475.         init = pgd_offset(&init_mm, 0);
  476.         memset (ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
  477.         memcpy (ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
  478.             (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
  479.     }
  480.     return ret;
  481. }
  482.  
  483. extern __inline__ pgd_t *get_pgd_fast(void)
  484. {
  485.     unsigned long *ret;
  486.  
  487.     if((ret = pgd_quicklist) != NULL) {
  488.         pgd_quicklist = (unsigned long *)(*ret);
  489.         ret[0] = ret[1];
  490.         pgtable_cache_size--;
  491.     } else
  492.         ret = (unsigned long *)get_pgd_slow();
  493.     return (pgd_t *)ret;
  494. }
  495.  
  496. extern __inline__ void free_pgd_fast(pgd_t *pgd)
  497. {
  498.     *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
  499.     pgd_quicklist = (unsigned long *) pgd;
  500.     pgtable_cache_size++;
  501. }
  502.  
  503. extern __inline__ void free_pgd_slow(pgd_t *pgd)
  504. {
  505.     free_page((unsigned long)pgd);
  506. }
  507.  
  508. extern pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
  509.  
  510. extern __inline__ pmd_t *get_pmd_fast(void)
  511. {
  512.     unsigned long *ret;
  513.  
  514.     if((ret = (unsigned long *)pte_quicklist) != NULL) {
  515.         pte_quicklist = (unsigned long *)(*ret);
  516.         ret[0] = ret[1];
  517.         pgtable_cache_size--;
  518.     }
  519.     return (pmd_t *)ret;
  520. }
  521.  
  522. extern __inline__ void free_pmd_fast(pmd_t *pmd)
  523. {
  524.     *(unsigned long *)pmd = (unsigned long) pte_quicklist;
  525.     pte_quicklist = (unsigned long *) pmd;
  526.     pgtable_cache_size++;
  527. }
  528.  
  529. extern __inline__ void free_pmd_slow(pmd_t *pmd)
  530. {
  531.     free_page((unsigned long)pmd);
  532. }
  533.  
  534. extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
  535.  
  536. extern __inline__ pte_t *get_pte_fast(void)
  537. {
  538.     unsigned long *ret;
  539.  
  540.     if((ret = (unsigned long *)pte_quicklist) != NULL) {
  541.         pte_quicklist = (unsigned long *)(*ret);
  542.         ret[0] = ret[1];
  543.         pgtable_cache_size--;
  544.     }
  545.     return (pte_t *)ret;
  546. }
  547.  
  548. extern __inline__ void free_pte_fast(pte_t *pte)
  549. {
  550.     *(unsigned long *)pte = (unsigned long) pte_quicklist;
  551.     pte_quicklist = (unsigned long *) pte;
  552.     pgtable_cache_size++;
  553. }
  554.  
  555. extern __inline__ void free_pte_slow(pte_t *pte)
  556. {
  557.     free_page((unsigned long)pte);
  558. }
  559.  
  560. extern void __bad_pte(pmd_t *pmd);
  561. extern void __bad_pmd(pgd_t *pgd);
  562.  
  563. #define pte_free_kernel(pte)    free_pte_fast(pte)
  564. #define pte_free(pte)        free_pte_fast(pte)
  565. #define pmd_free_kernel(pmd)    free_pmd_fast(pmd)
  566. #define pmd_free(pmd)        free_pmd_fast(pmd)
  567. #define pgd_free(pgd)        free_pgd_fast(pgd)
  568. #define pgd_alloc()        get_pgd_fast()
  569.  
  570. extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
  571. {
  572.     address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
  573.     if (pmd_none(*pmd)) {
  574.         pte_t *page = get_pte_fast();
  575.         
  576.         if (!page)
  577.             return get_pte_slow(pmd, address);
  578.         pmd_set(pmd, page);
  579.         return page + address;
  580.     }
  581.     if (pmd_bad(*pmd)) {
  582.         __bad_pte(pmd);
  583.         return NULL;
  584.     }
  585.     return (pte_t *) pmd_page(*pmd) + address;
  586. }
  587.  
  588. extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
  589. {
  590.     address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
  591.     if (pgd_none(*pgd)) {
  592.         pmd_t *page = get_pmd_fast();
  593.         
  594.         if (!page)
  595.             return get_pmd_slow(pgd, address);
  596.         pgd_set(pgd, page);
  597.         return page + address;
  598.     }
  599.     if (pgd_bad(*pgd)) {
  600.         __bad_pmd(pgd);
  601.         return NULL;
  602.     }
  603.     return (pmd_t *) pgd_page(*pgd) + address;
  604. }
  605.  
  606. #define pte_alloc_kernel    pte_alloc
  607. #define pmd_alloc_kernel    pmd_alloc
  608.  
  609. extern int do_check_pgt_cache(int, int);
  610.  
  611. extern inline void set_pgdir(unsigned long address, pgd_t entry)
  612. {
  613.     struct task_struct * p;
  614.     pgd_t *pgd;
  615.         
  616.     read_lock(&tasklist_lock);
  617.     for_each_task(p) {
  618.         if (!p->mm)
  619.             continue;
  620.         *pgd_offset(p->mm,address) = entry;
  621.     }
  622.     read_unlock(&tasklist_lock);
  623.     for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
  624.         pgd[(address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)] = entry;
  625. }
  626.  
  627. extern pgd_t swapper_pg_dir[1024];
  628.  
  629. /*
  630.  * The Alpha doesn't have any external MMU info:  the kernel page
  631.  * tables contain all the necessary information.
  632.  */
  633. extern inline void update_mmu_cache(struct vm_area_struct * vma,
  634.     unsigned long address, pte_t pte)
  635. {
  636. }
  637.  
  638. /*
  639.  * Non-present pages:  high 24 bits are offset, next 8 bits type,
  640.  * low 32 bits zero.
  641.  */
  642. extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
  643. { pte_t pte; pte_val(pte) = (type << 32) | (offset << 40); return pte; }
  644.  
  645. #define SWP_TYPE(entry) (((entry) >> 32) & 0xff)
  646. #define SWP_OFFSET(entry) ((entry) >> 40)
  647. #define SWP_ENTRY(type,offset) pte_val(mk_swap_pte((type),(offset)))
  648.  
  649. #define module_map    vmalloc
  650. #define module_unmap    vfree
  651.  
  652. /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
  653. #define PageSkip(page)        (0)
  654. #define kern_addr_valid(addr)    (1)
  655.  
  656. #endif /* _ALPHA_PGTABLE_H */
  657.